<?php

class Crud_Section_Column extends Base_AdminSectionPropertyRow
{
	/**
	 * @var Crud_Section
	 */
	protected $_section;
	
	/**
	 * Metadata of column.
	 * 
	 * @return array
	 */
	protected $_metadata;
	
	/**
	 * Map of column.
	 * 
	 * @return array
	 */
	protected $_map;
	
	/**
	 * Db type of column.
	 * 
	 * @var string
	 */
	protected $_type;
	
	/**
	 * Flag for column is foreign key or not.
	 * 
	 * @var boolean
	 */
	protected $_isForeignKey;
	
	/**
	 * FK table.
	 * 
	 * @var Crud_Section
	 */
	protected $_fkTable;
	
	/**
	 * Flag for column is unique key or not.
	 * 
	 * @var boolean
	 */
	protected $_isUnique;
	
	/**
	 * @return Crud_Section
	 */
	public function getSection()
	{
		return $this->getAdminSectionRowBySectionId();
		if (!$this->_section) {
			throw new Crud_Exception('Section for column is not set');
		}
		
		return $this->_section;
	}
	
	/**
	 * Return label of column.
	 * 
	 * @return string
	 */
	public function getLabel()
	{
		return $this->getName();
	}
	
	/**
	 * Return column type from Db.
	 * 
	 * @return string
	 */
	public function getType()
	{
		if ($this->_type) {
			return $this->_type;
		}
		
		$metadata = $this->_getMetadata();
		$this->_type = $metadata['DATA_TYPE'];
		return $this->_type;
	}
	
	/**
	 * Return column can be null or not.
	 * 
	 * @return boolean
	 */
	public function isNull()
	{
		$metadata = $this->_getMetadata();
		return $metadata['NULLABLE'];
	}
	
	/**
	 * Return max length of column.
	 * 
	 * @return integer
	 */
	public function getMaxLength()
	{
		$metadata = $this->_getMetadata();
		return $metadata['LENGTH'];
	}
	
	/**
	 * Return mysql default value of column.
	 * 
	 * @return mixed
	 */
	public function getDefault()
	{
		$metadata = $this->_getMetadata();
		return $metadata['DEFAULT'];
	}
	
	/**
	 * Return is column unsigned.
	 * 
	 * @return integer
	 */
	public function isUnsigned()
	{
		$metadata = $this->_getMetadata();
		return $metadata['UNSIGNED'];
	}
	
	/**
	 * Return true when column is foreign key.
	 * 
	 * @return boolean
	 */
	public function isFK()
	{
		if ($this->_isForeignKey !== null) {
			return $this->_isForeignKey;
		}
		
		$this->_isForeignKey = false;
		$map = $this->_getMap();
		if ($map) {
			$this->_isForeignKey = true;
		}
		
		return $this->_isForeignKey;
	}
	
	/**
	 * Return true when column is file.
	 * 
	 * @return boolean
	 */
	public function isFile()
	{
		if (substr($this->getKey(), 0, 4) == 'file') {
			return true;
		}
		
		return false;
	}
	
	public function isMany2many()
	{
		$name = $this->getKey();
		if (preg_match('/^[a-z_]+[a-z]2[a-z][a-z_]+$/i', $name)) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Return table by foreign key.
	 * 
	 * @return Crud_Section
	 */
	public function getFKTable()
	{
		if ($this->_fkTable !== null) {
			return $this->_fkTable;
		}
		
		if (!$this->isFK()) {
			$name = $this->getKey();
			throw new Crud_Exception("Column `$name` is not FK. Cant get FK table.");
		}
		
		$map = $this->_getMap();
		$peer = call_user_func(array($map['refTableClass'], 'getInstance'));
		$name = $peer->getName();
		
		$this->_fkTable = AdminSectionPeer::getInstance()->fetchByKey($name);
		if (!$this->_fkTable) {
			throw new Crud_Exception("Section with key `$name` is not exists");
		}
		
		return $this->_fkTable;
	}
	
	/**
	 * Get array of foreign key values.
	 * Key is ID. And value from reference table specified column.
	 * 
	 * @param integer $id
	 * @return array
	 */
	public function getFKValues($id = null, $filter = null)
	{
		$section = $this->getFKTable();
		$columnFK = $section->getPrimaryFKColumn();
		
		$table = $section->getPeer();
		$select = $table->select();
		if ($id) {
			$select->where("`id` = ?", $id);
		}
		
		if ($filter) {
			$select->where("`$columnFK` LIKE '%$filter%'");
		}
		
		$select->order($columnFK);
		$select->limit(500);
		
		$values = array();
		$rowset = $table->fetchAll($select);
		foreach ($rowset as $row) {
			$values[ $row->id ] = $row->$columnFK;
		}
		
		return $values;
	}
	
	/**
	 * Return FK values as tree.
	 * 
	 * @return Tree
	 */
	public function getFKValuesAsTree()
	{
		$table = $this->getFKTable();
		$peer = $table->getPeer();
		$columnFK = $table->getPrimaryFKColumn();

		$select = $peer->select();
		$select->order('parent_id');
		$select->limit(500);
		
		$rowset = $peer->fetchAll($select);
		
		$tree = new Tree();
		foreach ($rowset as $row) {
			$id = $row->getId();
			$parentId = $row->getParentId();
			if (!$parentId) {
				$tree->addRootNodeId($id);
			}
			
			$array = array(
				'id' => $id,
				'parent_id' => $parentId,
				'value' => $row->$columnFK,
			);
			
			$node = new TreeNode($id, $array);
			$tree->addNode($node);
			$parentNode = $tree->getNodeById($parentId);
			if ($parentNode) {
				$parentNode->addChild($node);
			}
		}
		
		foreach ($rowset as $row) {
			$id = $row->getId();
			$parentId = $row->getParentId();
			
			$node = $tree->getNodeById($id);
			$parentNode = $tree->getNodeById($parentId);
			if ($parentNode) {
				$parentNode->addChild($node);
			}
		}
		
		return $tree;
	}
	
	/**
	 * Get FK value by current column value.
	 * 
	 * @param integer $where
	 * @return string
	 */
	public function getFKValue($where)
	{
		$values = $this->getFKValues($where);
		return current($values);
	}
	
	/**
	 * Return true when column is unique key.
	 * 
	 * @return boolean
	 */
	public function isUnique()
	{
		if ($this->_isUnique !== null) {
			return $this->_isUnique;
		}
		
		$table = $this->getTable();
		$tableName = $table->getTableName();
		
		$adapter = $table->getAdapter();
        $sql = 'DESCRIBE ' . $adapter->quoteIdentifier($tableName, true);
        $stmt = $adapter->query($sql);

        $rowset = $stmt->fetchAll();
        $columnName = $this->getName();
		foreach ($rowset as $row) {
			if ($row['Field'] != $columnName) {
				continue;
			}
			
			$this->_isUnique = ($row['Key'] == 'UNI');
			return $this->_isUnique;
		}
		
		throw new Crud_Exception("Field `$columnName` is not exists in describe statement"); 
	}
	
	/**
	 * Return reference map for column if exists.
	 * 
	 * @return array|null
	 */
	protected function _getMap()
	{
		if ($this->_map !== null) {
			return $this->_map;
		}
		
		$maps = $this->getSection()->getMap();
		$map = false;
		foreach ($maps as $m) {
			if ($m['columns'] == $this->getKey()) {
				$map = $m;
				break;
			}
		}
		
		$this->_map = $map;
		return $this->_map;
	}
	
	/**
	 * Get metadata for column.
	 * 
	 * @return array
	 */
	public function _getMetadata()
	{
		if ($this->_metadata) {
			return $this->_metadata;
		}
		
		$section = $this->getSection();
		$metadata = $section->getMetadata();
		$metadata = $metadata[ $this->getKey() ];
		$this->_metadata = $metadata;
		return $this->_metadata;
	}
	
	/**
	 * Return array of filters for column.
	 * 
	 * @return array
	 */
	public function getFilters()
	{
		return array();
	}
	
	/**
	 * Return array of validators for column.
	 * 
	 * @return array
	 */
	public function getValidators()
	{
		return array();
	}
	
	/**
	 * Return getter method for column.
	 * 
	 * @return string
	 */
	public function getGetter()
	{
		$filter = new Zend_Filter_Word_UnderscoreToCamelCase();
		$name = ucfirst($filter->filter($this->getKey()));
		$name = str_replace('_', '', $name);
		return 'get' . $name;
	}
	
	/**
	 * Return setter method for column.
	 * 
	 * @return string
	 */
	public function getSetter()
	{
		$filter = new Zend_Filter_Word_UnderscoreToCamelCase();
		$name = ucfirst($filter->filter($this->getKey()));
		$name = str_replace('_', '', $name);
		return 'set' . $name;
	}
	
	/**
	 * Return value for show by value in DB.
	 * 
	 * @param string $value
	 * @return string
	 */
	public function getValue($value)
	{
		if ($this->isFile() && $value) {
			$prefix = Config::getInstance()->file_transfer->htdocsPath;
			$folder = substr($value, 0, 2);
			$value = "$prefix/$folder/$value";
			
			try {
				$url = Image_Replication::getInstance()->getPreview($value, 100, 100);
				$hostname = Config::getInstance()->default->hostname ? Config::getInstance()->default->hostname : null;
				if ($hostname) $hostname = "http://$hostname";
				$value = "<a href='{$hostname}{$value}'><img src='{$hostname}{$url}' width='100' height='100'></img></a>";
			} catch (Image_Exception $e) {
				$value = 'Файл не найден';
			}
		} else if ($this->isFK() && $value) {
			$section = $this->getFKTable();
			$peer = $section->getPeer();
			$row = $peer->find($value)->current();
			$id = $value;
			if (!$row) {
				throw new Crud_Exception("Foreign key `{$this->getSection()->getKey()}`.`{$this->getKey()}` has invalid value: `$value`");
			}
			
			$columnFK = $section->getPrimaryFKColumn();
			$value = $row->__get($columnFK);
			$value = "<a href='/admin/crud/edit/table/{$section->getKey()}/id/{$id}'>$value</a>";
		} else if (in_array($this->getType(), array('date', 'datetime', 'timestamp'))) {
			if ($value == '0000-00-00') {
				$value = null;
			}

			
			if ($value) {
				$value = preg_replace('/(\d{4})\-(\d{2})\-(\d{2})/', "$3.$2.$1", $value);
			}
		} else if (substr($value, 0, 7) == 'http://') {
			$value = "<a href='$value' target='_blank'>$value</a>";
		} else if (($this->getKey() == 'log') && ($this->getSection()->getKey() == 'admin_log')) {
		} else {
			$value = htmlspecialchars($value);
		}
		
		return $value;
	}
}
